package com.xinqi.common.security.config;

import cn.dev33.satoken.interceptor.SaInterceptor;
import com.xinqi.common.base.current.Currents;
import com.xinqi.common.base.error.exception.ErrorResponseException;
import com.xinqi.common.base.response.R;
import com.xinqi.common.base.user.Account;
import com.xinqi.common.satoken.utils.LoginHelper;
import com.xinqi.common.security.filter.SaInnerServletFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpStatus;
import org.springframework.lang.Nullable;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

import javax.servlet.Filter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 权限安全配置
 *
 * @author dgyu
 */
@Slf4j
@AutoConfiguration
public class SecurityConfiguration implements WebMvcConfigurer {

    /**
     * 注册sa-token的拦截器，用于Controller接口权限校验
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 注册路由拦截器，自定义验证规则
        registry.addInterceptor(new SaInterceptor()).addPathPatterns("/**");
        registry.addInterceptor(new CurrentHandlerInterceptor()).addPathPatterns("/**");
    }

    /**
     * 校验是否从 网关转发 或者 OpenFeign调用
     */
    @Bean
    public Filter getSaServletFilter() {
        return new SaInnerServletFilter()
            .addInclude("/**")
            .addExclude("/v3/api-docs", "/*Login", "/sms/code", "/ems/code", "/**/dict/data/**", "/**/register", "/**/login", "/**/password", "/**/logout", "/actuator/**", "/inner/**", "/websocket/**")
            .setAuth(obj -> LoginHelper.checkSameToken())
            .setError(e -> {
                if (e instanceof ErrorResponseException) {
                    return ((ErrorResponseException) e).getResult();
                }
                return R.error(HttpStatus.INTERNAL_SERVER_ERROR.value(), "服务器繁忙，请稍后重试");
            });
    }

    public static class CurrentHandlerInterceptor implements HandlerInterceptor {
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
            // 当前用户
            Account account;
            try {
                // 获取 SaToken中的用户信息
                account = LoginHelper.getXqLoginUser();
                if (account != null) {
                    // 保存当前用户上下文
                    Currents.put(account);
                }
            } catch (Exception e) {
                log.warn("Failed to obtain user context!");
            }
            return true;
        }

        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
                                    @Nullable Exception ex) throws Exception {
            // 移除当前用户上下文
            Currents.remove(Account.class);
        }
    }
}
